package piis;

import java.io.FileWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JFrame;

import org.jfree.ui.RefineryUtilities;

import Algorithms.BackPropagation;
import Algorithms.LinearRegression;
import MainProgram.SinusCreator;
import NeuronNetworkLibrary.Network;

public class LinearRegressionSinus {


    public final static int EPOCH = 5;
    public final static double ERROR = 0.000001;
	
	public static void main(String[] args) {
			
		//First, create a point cloud that fit with the sinus function and then can use it as input for the regression
		Random r = new Random();
	        double obtainedResults[][];
	        SinusCreator data = new SinusCreator(100);
	        Network network = new Network(data.getTrainingSet(), data.getDesiredOutput(),new int[]{3}, new String[]{"sigmo"}, "output");
	        int k;
	        int i = 1;
	        while (i <= EPOCH) {
	            k = r.nextInt(network.getNumberOfPatterns());
	            network.calculateNetwork(k);
	            BackPropagation.calculateBackPropagation(network);
	            i++;
	        }
	        obtainedResults = printFinalResults(network);
	        
	        //Number or parameters(degree of the poly+1)
	        
            int numb = 16;
                
	        double[] tset = data.getXValues();
	        //Prepare the X matrix with the training set
	        double[][] x = new double[numb][tset.length];
	        for(i=1; i < numb ; i++){
	        	for(int j=0;j<tset.length; j++){
	        		x[i-1][j] = Math.pow(tset[j], i);
	        	}
	        }
	        //Prepare the Y matrix with the obtainedResults
	        double[] y = obtainedResults[0];
	        
	        //Create the linealRegression with this two matrix
	        
	        LinearRegression linealR = new LinearRegression(x,y,numb);
	        
	        //Execute the algorithm
	        linealR.gradientDescent();
	        
	        
	        
	
	        // Preparation of data for the plot.
	        Map<Double,Double> map = new HashMap<>();
	        for(double j = 0; j <= tset[tset.length-1]; j+=0.01){
	        	map.put(Double.valueOf(j), linealR.func(j));
	        }
	        

	        
	        // Create a plot.
	        Plot demo = new Plot("Assignment 2","Sinus",map,obtainedResults,data.getTrainingSet());
	        demo.pack();
	        RefineryUtilities.centerFrameOnScreen(demo);
	        demo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	        demo.setVisible(true);
		        	
	        double[] errors = linealR.getErrors();
	        try{
	        	FileWriter errorsF = new FileWriter("src/prueba_train.out");
	          	             
	  	        for(int i1 = 0; i1<errors.length; i1++){
	  	        	errorsF.write(errors[i1] + "\r\n");
	  	        }
	        	
	  	        errorsF.close();
	  	        
	        }catch(Exception e){
	        	e.printStackTrace();
	        }
	        
		}
	 
	
	    private static double[][] printFinalResults(Network network) {

	        int patternNumber = network.getNumberOfPatterns();
	        int patternLength = network.getOutputLayer().size();
	        
	        double[][] obtainedResults = new double[patternNumber][patternLength];
	        for (int i = 0; i < network.getNumberOfPatterns(); i++) {
	            network.calculateNetwork(i);

	            for (int j = 0; j < network.getOutputLayer().size(); j++) {
	                obtainedResults[i][j] = network.getOutputLayer().get(j).getCalculatedOutput();
	            }
	        }
	        
	        return obtainedResults;
	    }


}
